home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / editor / j414src.arc / KEYMAPS.C < prev    next >
C/C++ Source or Header  |  1989-10-10  |  13KB  |  626 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. #include "jove.h"
  9. #include "list.h"
  10. #include "fp.h"
  11. #include "termcap.h"
  12. #include "chars.h"
  13. #include "disp.h"
  14. #include "re.h"
  15.  
  16. /* Up until now a keymap was an array of pointers to
  17.    data_obj's.  A data_obj was either a pointer to a built-in
  18.    command or a keyboard macro.  Now a data_obj can be a
  19.    pointer to a keymap as well, which is how prefix keys will
  20.    be handled.
  21.  
  22.    There will be a way to build keymaps and give them names,
  23.    and to look those keymaps up by name, attach them to keys.
  24.    There will be a way to specify a string of key strokes and
  25.    have a series of keymaps built automatically for those
  26.    sequences. */
  27.  
  28. private    void
  29.     fb_aux proto((data_obj *, struct keymap *, char *, char *)),
  30.     find_binds proto((data_obj *, char *));
  31.  
  32. private List    *keymaps;        /* list of all keymaps */
  33. private struct keymap    *mainmap;
  34. #if defined(IPROCS)
  35. private struct keymap    *procsmap;
  36. #endif
  37.  
  38. /* make a new keymap, give it name NAME, initialize the keys array
  39.    to keys, if nonzero, or make an empty one, otherwise */
  40.  
  41. private struct keymap *
  42. km_new(name, keys)
  43. char    *name;
  44. data_obj    **keys;
  45. {
  46.     struct keymap    *km;
  47.  
  48.     km = (struct keymap *) emalloc(sizeof *km);
  49.     (void) list_push(&keymaps, (Element *) km);
  50.     km->Type = KEYMAP;
  51.     km->Name = name;
  52.     if (keys != 0) {
  53.         km->k_keys = keys;
  54.         km->k_alloc_p = NO;
  55.     } else {
  56.         km->k_keys = (data_obj **) emalloc(NCHARS * sizeof (data_obj *));
  57.         byte_zero((char *) km->k_keys, NCHARS * sizeof (data_obj *));
  58.         km->k_alloc_p = YES;
  59.     }
  60.     return km;
  61. }
  62.  
  63. #ifdef    NEVER_USED
  64.  
  65. /* free up a keymap */
  66.  
  67. private void
  68. km_destroy(km)
  69. struct keymap    *km;
  70. {
  71.     if (km->k_alloc_p == YES)
  72.         free((char *) km->k_keys);
  73.     km->k_keys = 0;
  74.     free((char *) km);
  75. }
  76.  
  77. /* lookup a keymap by name */
  78.  
  79. private struct keymap *
  80. km_lookup(name)
  81. char    *name;
  82. {
  83.     List    *lp;
  84.  
  85.     for (lp = keymaps; lp != 0; lp = list_next(lp))
  86.         if (strcmp(name, ((struct keymap *) list_data(lp))->Name) == 0)
  87.             break;
  88.     if (lp == 0)
  89.         return 0;
  90.     return (struct keymap *) list_data(lp);
  91. }
  92.  
  93. #endif
  94.  
  95. /* given a map and a key, return the object bound to that key */
  96.  
  97. #define km_getkey(m, c)    ((m)->k_keys[(c) & CHARMASK])
  98.  
  99. #ifndef km_getkey
  100. data_obj *
  101. km_getkey(m, c)
  102. struct keymap    *m;
  103. int    c;
  104. {
  105.     return (m->k_keys[c & CHARMASK]);
  106. }
  107. #endif
  108.  
  109. private void
  110. km_setkey(m, c, d)
  111. struct keymap    *m;
  112. int    c;
  113. data_obj    *d;
  114. {
  115.     m->k_keys[c & CHARMASK] = d;
  116. }
  117.  
  118. /* get the currently active keymaps into km_buf */
  119.  
  120. private int
  121. get_keymaps(km_buf)
  122. struct keymap    **km_buf;
  123. {
  124.     int    nmaps = 0;
  125.  
  126. #ifdef IPROCS
  127.     if (curbuf->b_process != 0)
  128.         km_buf[nmaps++] = procsmap;
  129. #endif
  130.     if (curbuf->b_map != 0)
  131.         km_buf[nmaps++] = curbuf->b_map;
  132.     km_buf[nmaps++] = mainmap;
  133.  
  134.     return nmaps;
  135. }
  136.  
  137. private struct keymap *
  138. IsPrefix(cp)
  139. data_obj    *cp;
  140. {
  141.     if (cp == 0 || (cp->Type & TYPEMASK) != KEYMAP)
  142.         return 0;
  143.     return (struct keymap *) cp;
  144. }
  145.  
  146. /* Is `c' a prefix character */
  147.  
  148. int
  149. PrefChar(c)
  150. int    c;
  151. {
  152.     return (int) IsPrefix(km_getkey(mainmap, c));
  153. }
  154.  
  155. void
  156. UnbindC()
  157. {
  158.     char    *keys;
  159.     struct keymap    *map = mainmap;
  160.  
  161.     keys = ask((char *) 0, ProcFmt);
  162.     for (;;) {
  163.         if (keys[1] == '\0')
  164.             break;
  165.         if ((map = IsPrefix(km_getkey(map, *keys))) == 0)
  166.             break;
  167.         keys += 1;
  168.     }
  169.     if (keys[1] != 0)
  170.         complain("That's not a legitimate key sequence.");
  171.     km_setkey(map, keys[0], (data_obj *) 0);
  172. }
  173.  
  174. void
  175. BindWMap(map, lastkey, cmd)
  176. struct keymap    *map;
  177. int    lastkey;
  178. data_obj     *cmd;
  179. {
  180.     struct keymap    *nextmap;
  181.     int    c;
  182.  
  183.     c = addgetc();
  184.     if (c == EOF) {
  185.         if (lastkey == EOF)
  186.             complain("[Empty key sequence]");
  187.         complain("[Premature end of key sequence]");
  188.     } else {
  189.         if ((nextmap = IsPrefix(km_getkey(map, c))) != NULL)
  190.             BindWMap(nextmap, c, cmd);
  191.         else {
  192.             km_setkey(map, c, cmd);
  193. #ifdef MAC
  194.             ((struct cmd *) cmd)->c_key = c;    /* see about_j() in mac.c */
  195.             if (map->k_keys == MainKeys)
  196.                 ((struct cmd *) cmd)->c_map = F_MAINMAP;
  197.             else if (map->k_keys == EscKeys)
  198.                 ((struct cmd *) cmd)->c_map = F_PREF1MAP;
  199.             else if (map == (struct keymap *) CtlxKeys)
  200.                 ((struct cmd *) cmd)->c_map = F_PREF2MAP;
  201. #endif
  202.         }
  203.     }
  204. }
  205.  
  206. void
  207. BindSomething(proc, map)
  208. #if defined(MAC) || defined(IBMPC)
  209. data_obj    *(*proc)();
  210. #else
  211. data_obj    *(*proc) proto((char *));
  212. #endif
  213. struct keymap    *map;
  214. {
  215.     data_obj    *d;
  216.  
  217.     if ((d = (*proc)(ProcFmt)) == 0)
  218.         return;
  219.     s_mess(": %f %s ", d->Name);
  220.     BindWMap(map, EOF, d);
  221. }
  222.  
  223. void
  224. BindAKey()
  225. {
  226.     BindSomething(findcom, mainmap);
  227. }
  228.  
  229. void
  230. BindMac()
  231. {
  232.     BindSomething(findmac, mainmap);
  233. }
  234.  
  235. void
  236. DescWMap(map, key)
  237. struct keymap    *map;
  238. int    key;
  239. {
  240.     data_obj    *cp = km_getkey(map, key);
  241.     struct keymap    *prefp;
  242.  
  243.     if (cp == 0)
  244.         add_mess("is unbound.");
  245.     else if ((prefp = IsPrefix(cp)) != NULL)
  246.         DescWMap(prefp, addgetc());
  247.     else
  248.         add_mess("is bound to %s.", cp->Name);
  249. }
  250.  
  251. void
  252. KeyDesc()
  253. {
  254.     s_mess(ProcFmt);
  255.     DescWMap(mainmap, addgetc());
  256. }
  257.  
  258. void
  259. DescBindings()
  260. {
  261.     TOstart("Key Bindings", TRUE);
  262.     DescMap(mainmap, NullStr);
  263.     TOstop();
  264. }
  265.  
  266. void
  267. DescMap(map, pref)
  268. struct keymap    *map;
  269. char    *pref;
  270. {
  271.     int    c1,
  272.         c2 = 0,
  273.         numbetween;
  274.     char    keydescbuf[40];
  275.     struct keymap    *prefp;
  276.  
  277.     for (c1 = 0; c1 < NCHARS && c2 < NCHARS; c1 = c2 + 1) {
  278.         c2 = c1;
  279.         if (km_getkey(map, c1) == 0)
  280.             continue;
  281.         while (++c2 < NCHARS && km_getkey(map, c1) == km_getkey(map, c2))
  282.             ;
  283.         c2 -= 1;
  284.         numbetween = c2 - c1;
  285.         if (numbetween == 1)
  286.             swritef(keydescbuf, "%s {%p,%p}", pref, c1, c2);
  287.         else if (numbetween == 0)
  288.             swritef(keydescbuf, "%s %p", pref, c1);
  289.         else
  290.             swritef(keydescbuf, "%s [%p-%p]", pref, c1, c2);
  291.         if ((prefp = IsPrefix(km_getkey(map, c1)))!=NULL && (prefp != map))
  292.             DescMap(prefp, keydescbuf);
  293.         else
  294.             Typeout("%-18s%s", keydescbuf, km_getkey(map, c1)->Name);
  295.     }
  296. }
  297.  
  298. private void
  299. find_binds(dp, buf)
  300. data_obj    *dp;
  301. char    *buf;
  302. {
  303.     char    *endp;
  304.  
  305.     buf[0] = '\0';
  306.     fb_aux(dp, mainmap, (char *) 0, buf);
  307.     endp = buf + strlen(buf) - 2;
  308.     if ((endp > buf) && (strcmp(endp, ", ") == 0))
  309.         *endp = '\0';
  310. }
  311.  
  312. private void
  313. fb_aux(cp, map, prefix, buf)
  314. register data_obj    *cp;
  315. struct keymap    *map;
  316. char    *buf,
  317.     *prefix;
  318. {
  319.     int    c1,
  320.         c2;
  321.     char    *bufp = buf + strlen(buf),
  322.         prefbuf[20];
  323.     struct keymap    *prefp;
  324.  
  325.     for (c1 = c2 = 0; c1 < NCHARS && c2 < NCHARS; c1 = c2 + 1) {
  326.         c2 = c1;
  327.         if (km_getkey(map, c1) == cp) {
  328.             while (++c2 < NCHARS && km_getkey(map, c1) == km_getkey(map, c2))
  329.                 ;
  330.             c2 -= 1;
  331.             if (prefix)
  332.                 swritef(bufp, "%s ", prefix);
  333.             bufp += strlen(bufp);
  334.             switch (c2 - c1) {
  335.             case 0:
  336.                 swritef(bufp, "%p, ", c1);
  337.                 break;
  338.  
  339.             case 1:
  340.                 swritef(bufp, "{%p,%p}, ", c1, c2);
  341.                 break;
  342.  
  343.             default:
  344.                 swritef(bufp, "[%p-%p], ", c1, c2);
  345.                 break;
  346.             }
  347.         }
  348.         if ((prefp = IsPrefix(km_getkey(map, c1)))!=NULL && (prefp != map))  {
  349.             swritef(prefbuf, "%p", c1);
  350.             fb_aux(cp, prefp, prefbuf, bufp);
  351.         }
  352.         bufp += strlen(bufp);
  353.     }
  354. }
  355.  
  356. void
  357. DescCom()
  358. {
  359.     data_obj    *dp;
  360.     char    pattern[100],
  361.         *doc_type,
  362.         *file = CmdDb;
  363.     static char var_type[] = "Variable";
  364.     static char cmd_type[] = "Command";
  365.     File    *fp;
  366.  
  367.     if (!strcmp(LastCmd->Name, "describe-variable")) {
  368.         doc_type = var_type;
  369.         dp = (data_obj *) findvar(ProcFmt);
  370.     } else {
  371.         doc_type = cmd_type;
  372.         dp = (data_obj *) findcom(ProcFmt);
  373.     }
  374.     if (dp == 0)
  375.         return;
  376.     fp = open_file(file, iobuff, F_READ, YES, YES);
  377.     Placur(ILI, 0);
  378.     flusho();
  379.     swritef(pattern, "^:entry \"%s\" \"%s\"$", dp->Name, doc_type);
  380.     TOstart("Help", TRUE);
  381.     for (;;) {
  382.         if (f_gets(fp, genbuf, (size_t)LBSIZE) == EOF) {
  383.             Typeout("There is no documentation for \"%s\".", dp->Name);
  384.             break;
  385.         }
  386.         if (genbuf[0] == ':' && LookingAt(pattern, genbuf, 0)) {
  387.             /* found it ... let's print it */
  388.             if (doc_type == var_type)
  389.                 Typeout(dp->Name);
  390.             else if (doc_type == cmd_type) {
  391.                 char    binding[128];
  392.  
  393.                 find_binds(dp, binding);
  394.                 if (blnkp(binding))
  395.                     Typeout("To invoke %s, type \"ESC X %s<cr>\".",
  396.                         dp->Name, dp->Name);
  397.                 else
  398.                     Typeout("Type \"%s\" to invoke %s.",
  399.                         binding, dp->Name);
  400.             }
  401.             Typeout("");
  402.             while (f_gets(fp, genbuf, (size_t)LBSIZE) != EOF
  403.             && strncmp(genbuf, ":entry", (size_t)6) != 0) {
  404.                 Typeout("%s", genbuf);
  405.             }
  406.             break;
  407.         }
  408.     }
  409.     f_close(fp);
  410.     TOstop();
  411. }
  412.  
  413.  
  414. void
  415. Apropos()
  416. {
  417.     register const struct cmd    *cp;
  418.     register struct macro    *m;
  419.     register const struct variable    *v;
  420.     char    *ans;
  421.     int    anyfs = NO,
  422.         anyvs = NO,
  423.         anyms = NO;
  424.     char    buf[256];
  425.  
  426.     ans = ask((char *) 0, ": %f (keyword) ");
  427.     TOstart("Help", TRUE);
  428.     for (cp = commands; cp->Name != 0; cp++)
  429.         if (sindex(ans, cp->Name)) {
  430.             if (anyfs == 0) {
  431.                 Typeout("Commands");
  432.                 Typeout("--------");
  433.             }
  434.             find_binds((data_obj *) cp, buf);
  435.             if (buf[0])
  436.                 Typeout(": %-35s (%s)", cp->Name, buf);
  437.             else
  438.                 Typeout(": %s", cp->Name);
  439.             anyfs = YES;
  440.         }
  441.     if (anyfs)
  442.         Typeout(NullStr);
  443.     for (v = variables; v->Name != 0; v++)
  444.         if (sindex(ans, v->Name)) {
  445.             if (anyvs == 0) {
  446.                 Typeout("Variables");
  447.                 Typeout("---------");
  448.             }
  449.             anyvs = YES;
  450.             vpr_aux(v, buf);
  451.             Typeout(": set %-26s %s", v->Name, buf);
  452.         }
  453.     if (anyvs)
  454.         Typeout(NullStr);
  455.     for (m = macros; m != 0; m = m->m_nextm)
  456.         if (sindex(ans, m->Name)) {
  457.             if (anyms == 0) {
  458.                 Typeout("Macros");
  459.                 Typeout("------");
  460.             }
  461.             anyms = YES;
  462.             find_binds((data_obj *) m, buf);
  463.             if (buf[0])
  464.                 Typeout(": %-35s (%s)", m->Name, buf);
  465.             else
  466.                 Typeout(": %-35s %s", "execute-macro", m->Name);
  467.         }
  468.     TOstop();
  469. }
  470.  
  471. #ifdef    NEVER_USED
  472. private char *
  473. km_newname()
  474. {
  475.     char    buffer[128];
  476.     static int    km_count = 1;
  477.  
  478.     swritef(buffer, "keymap-%d", km_count++);
  479.     return copystr(buffer);
  480. }
  481. #endif
  482.  
  483. void
  484. InitKeymaps()
  485. {
  486.     struct keymap    *km;
  487.  
  488.     mainmap = km_new(copystr("mainmap"), MainKeys);
  489.  
  490.     /* setup ESC map */
  491.     km = km_new(copystr("ESC-map"), EscKeys);
  492.     km_setkey(mainmap, ESC, (data_obj *) km);
  493.  
  494.     /* setup Ctlx map */
  495.     km = km_new(copystr("CTLX-map"), CtlxKeys);
  496.     km_setkey(mainmap, CTL('X'), (data_obj *) km);
  497.  
  498. #ifdef IBMPC
  499.     /* setup Misc map */
  500.     km = km_new(copystr("MISC-map"), MiscKeys);
  501.     km_setkey(mainmap, 0x00FF, (data_obj *) km);
  502. #endif
  503. }
  504.  
  505. void
  506. MakeKMap()
  507. {
  508.     char    *name;
  509.  
  510.     name = ask((char *) 0, ProcFmt);
  511.     (void) km_new(copystr(name), (data_obj **) 0);
  512. }
  513.  
  514. private data_obj *
  515. findmap(fmt)
  516. char    *fmt;
  517. {
  518.     List    *lp;
  519.     char    *strings[128];
  520.     int    i;
  521.  
  522.     for (lp = keymaps, i = 0; lp != 0; lp = list_next(lp))
  523.         strings[i++] = ((struct keymap *) list_data(lp))->Name;
  524.     strings[i] = 0;
  525.  
  526.     i = complete(strings, fmt, 0);
  527.     if (i < 0)
  528.         return 0;
  529.     lp = keymaps;
  530.     while (--i >= 0)
  531.         lp = list_next(lp);
  532.     return (data_obj *) list_data(lp);
  533. }
  534.  
  535. #ifdef IPROCS
  536. private void
  537. mk_proc_km()
  538. {
  539.     procsmap = km_new("process-keymap", (data_obj **) 0);
  540. }
  541.  
  542. void
  543. ProcBind()
  544. {
  545.     data_obj    *d;
  546.  
  547.     if (procsmap == 0)
  548.         mk_proc_km();
  549.  
  550.     if ((d = findcom(ProcFmt)) == 0)
  551.         return;
  552.     s_mess(": %f %s ", d->Name);
  553.     BindWMap(procsmap, EOF, d);
  554. }
  555.  
  556. void
  557. ProcKmBind()
  558. {
  559.     data_obj    *d;
  560.  
  561.     if (procsmap == 0)
  562.         mk_proc_km();
  563.     if ((d = findmap(ProcFmt)) == 0)
  564.         return;
  565.     s_mess(": %f %s ", d->Name);
  566.     BindWMap(procsmap, EOF, d);
  567. }
  568.  
  569. #endif
  570.  
  571. void
  572. KmBind()
  573. {
  574.     BindSomething(findmap, mainmap);
  575. }
  576.  
  577. void
  578. dispatch(c)
  579. register int    c;
  580. {
  581.     data_obj    *cp;
  582.     struct keymap    *maps[10];    /* never more than 10 active
  583.                        maps at a time, I promise */
  584.     int    nmaps;
  585.  
  586.     this_cmd = 0;
  587.     nmaps = get_keymaps(maps);
  588.  
  589.     for (;;) {
  590.         int    i,
  591.             nvalid,
  592.             slow = NO;
  593.  
  594.         for (i = 0, nvalid = 0; i < nmaps; i++) {
  595.             if (maps[i] == 0)
  596.                 continue;
  597.             cp = km_getkey(maps[i], c);
  598.             if (cp != 0) {
  599.                 if (obj_type(cp) != KEYMAP) {
  600.                     ExecCmd(cp);
  601.                     return;
  602.                 }
  603.                 nvalid += 1;
  604.             }
  605.             maps[i] = (struct keymap *) cp;
  606.         }
  607.         if (nvalid == 0) {
  608.             char    strokes[128];
  609.  
  610.             pp_key_strokes(strokes, sizeof (strokes));
  611.             s_mess("[%sunbound]", strokes);
  612.             rbell();
  613.             clr_arg_value();
  614.             errormsg = NO;
  615.             return;
  616.         }
  617.  
  618.         c = waitchar(&slow);
  619.         if (c == AbortChar) {
  620.             message("[Aborted]");
  621.             rbell();
  622.             return;
  623.         }
  624.     }
  625. }
  626.